﻿namespace HuwmanCode.ComponentModel.Composition.Hosting

open System
open System.Configuration
open System.ComponentModel.Composition
open System.ComponentModel.Composition.Hosting
open System.ComponentModel.Composition.Primitives
open System.Reflection

open HuwmanCode
open HuwmanCode.Reflection
open HuwmanCode.ComponentModel.Composition

type ApplicationSettingExportProvider (settings:ApplicationSettingsBase option) =
    inherit ExportProvider ()
    let getAppSettings () =
        let appSettings = 
            seq { for key in ConfigurationManager.AppSettings do
                    yield key,box(ConfigurationManager.AppSettings.[key]) }

        match settings with
        | None -> appSettings
        | Some settings ->
            let ts:seq<SettingsProperty> = settings.Properties |> Seq.cast
            ts 
            |> Seq.map (fun s -> s.Name,settings.[s.Name])
            |> Seq.append (appSettings)
            |> Seq.distinct       

    let getExports (definition:ImportDefinition) =
        if definition.ContractName |> String.IsNullOrWhiteSpace then None
        elif definition.Cardinality <> ImportCardinality.ZeroOrOne && definition.Cardinality <> ImportCardinality.ExactlyOne then None
        else let getMetadata (t:Type) = dict [(CompositionConstants.ExportTypeIdentityMetadataName, box (t.FullName))]
             let appSettings = getAppSettings ()
             appSettings
             |> Seq.map (fun (k,v) -> 
                let exportDefinition = new ExportDefinition (k, getMetadata (v.GetType()))
                let export = new Export (exportDefinition, fun () -> v)
                export)
             |> Seq.filter (fun e -> definition.IsConstraintSatisfiedBy (e.Definition))
             |> Some

    new (settings) = new ApplicationSettingExportProvider (Some settings)
    new () = new ApplicationSettingExportProvider (None)

    override this.GetExportsCore (definition, atomicComposition) = 
        match getExports definition with 
        | None -> Seq.empty
        | Some exports -> exports